/**
 * 合并配置
 * @param option 配置
 * @param data 数据
 * @returns {any} 配置和数据的集合
 */
function merge(option, data) {
  const newOption = JSON.parse(JSON.stringify(option), function (key, item) {
    if (
      typeof item === "string" &&
      (/^(data|dataJson)\./.test(item) || /^(window)\./.test(item))
    ) {
      const fields = item.split(".");
      if (fields[0] === "dataJson") {
        fields[0] = "data";
      }
      return fields.reduce(
        function (current, item, index) {
          try {
            if (index === 0) {
              return current;
            }
            return current[item];
          } catch (e) {
            return {};
          }
        },
        fields[0] === "window" ? window : data
      );
    }
    return item;
  });
  return newOption;
}

/**
 * 日志打印，为了方便压缩编译的清理
 * @type {{warn: log.warn, log: log.log, error: log.error, info: log.info}}
 */
const log = {
  info: function (...args) {
    console.info(...args);
  },
  error: function (...args) {
    console.error(...args);
  },
  log: function (...args) {
    console.log(...args);
  },
  warn: function (...args) {
    console.warn(...args);
  },
};

const commonMixin = {
  props: {
    config: {
      type: Object,
    },
    location: {
      type: Object,
    },
    request: {
      type: Object,
    },
    id: {
      type: String,
    },
  },
  data() {
    return {
      baseUrl: "",
      currentUrl: "",
    };
  },
  watch: {
    config: {
      handler() {
        this.update();
      },
      deep: true,
    },
  },
  mounted() {
    if (this.request.dataType === "STATIC") {
      this.init();
    } else if (this.request.dataType === "DYNAMIC") {
      let query = "";

      Object.keys(this.request.params).forEach((key, index) => {
        if (index === 0) {
          query += key + "=" + this.request.params[key];
        } else {
          query += "&" + key + "=" + this.request.params[key];
        }
      });
      $.ajax({
        url: window.$path + this.request.url + "?" + query,
        method: this.request.method,
        success: (res) => {
          if (!this.request.responseKey) {
            log.info(res);
            this.setData(res);
            return;
          }

          const fields = this.request.responseKey.split(".");
          const data = fields.reduce((current, key) => {
            try {
              return current[key];
            } catch (e) {
              log.error(e);
              return {};
            }
          }, res);
          log.info(data);
          this.setData(data);
        },
      });
    } else {
      log.warn("[datav.wran]: " + this.id + " 组件没有静态数据以及动态数据");
    }
  },
  methods: {
    init() {},
    update() {},
    setOption(data, id) {
      if (id) {
        console.log("设置指定的id 的配置");
        window.PubSub.publish("set-option", { id: id, data: data });
        return;
      }
      window.PubSub.publish("set-option", { id: this.id, data: data });
    },
    setData(data, id) {
      if (id) {
        console.log("设置指定的id 的数据");
        window.PubSub.publish("set-data", { id: id, data: data });
        return;
      }
      log.info(data, "setData");
      window.PubSub.publish("set-data", { id: this.id, data: data });
    },
    on(name, data) {
      console.info(name, data);
      window.PubSub.publish(name, data);
    },
    emit(name, fn) {
      window.PubSub.subscribe(name, function (name, data) {
        fn(data);
      });
    },
    after() {
      if (
        window["box" + this.id + "_after"] &&
        typeof window["box" + this.id + "_after"] === "function"
      ) {
        window["box" + this.id + "_after"].call(null, {
          setOption: this.setOption,
          setData: this.setData,
          on: this.on,
          emit: this.emit,
        });
      }
    },
  },
};

/**
 * 列表组件
 */
const vTable = {
  template: `
      <div class="v-s-table">
      <ul
          class="list-title"
          :style="{ height: config.height, 'background-color': config.titlebg }"
      >
        <li
            class="list-title-item"
            v-for="item in config.titles"
            :key="item.key"
            :style="{
          width: item.width,
          'justify-content': item.align,
          height: config.titleHeight,
        }"
        >
          {{ item.title }}
        </li>
      </ul>
      <div class="list-body" :style="tbodyStyle" :key="key">
        <div class="swiper" ref="swiper">
          <div class="swiper-wrapper">
            <div
                class="swiper-slide"
                v-for="(item, index) in config.list"
                :key="index"
                :style="{ height: config.rowHeight }"
            >
              <ul
                  class="list-item"
                  :class="index % 2 === 0 ? 'list-item-odd' : 'list-item-singular'"
                  :style="{ 'background-color': config.rowbg }"
              >
                <li
                    v-for="it in config.titles"
                    :key="it.key"
                    :style="{ width: it.width, 'justify-content': it.align }"
                >
                  <template v-if="it.key === 'index'">{{ index + 1 }}</template>
                  <template v-else>
                    <component v-if="it.key.indexOf('v-') !== -1" :is="it.key" :item="item" :field="it.key"></component>
                    <span v-else>
                      {{ item[it.key] }}
                  </span>

                  </template>
                </li>
              </ul>
            </div>
          </div>
        </div>
      </div>
      </div>
    `,
  name: "v-table",
  mixins: [commonMixin],
  data() {
    return {
      swiper: null,
      key: 0,
    };
  },

  computed: {
    tbodyStyle() {
      return {
        height: `calc(100% - ${this.config.titleHeight})`,
      };
    },
  },
  methods: {
    init() {
      this.initSwiper();
    },
    initSwiper() {
      if (this.swiper) {
        this.swiper.destroy();
        this.key++;
      }
      this.$nextTick(() => {
        this.swiper = new window.Swiper(
          this.$refs.swiper,
          this.config.swiperConfig
        );
      });
    },
    update() {
      this.initSwiper();
      if (
        window["box" + this.id + "_after"] &&
        typeof window["box" + this.id + "_after"] === "function"
      ) {
        window["box" + this.id + "_after"].call(null, {
          setOption: this.setOption,
          setData: this.setData,
          on: this.on,
          emit: this.emit,
        });
      }
    },
  },
};
/**
 * 地图图表组件
 */
const vMapChart = {
  template: `
      <div style="width: 100%; height: 100%" ref="chart"></div>
    `,
  name: "v-map-chart",
  mixins: [commonMixin],
  methods: {
    init() {
      if (!window._charts) {
        window._charts = {};
      }
      this.$nextTick(() => {
        window._charts[this.id] = window.echarts.init(this.$refs.chart);
        $.get("./map/" + this.config.climecode + ".json", (res) => {
          window.echarts.registerMap(this.config.climecode, res);
          window._charts[this.id].setOption(this.config.option, true);
          if (
            window["box" + this.id + "_after"] &&
            typeof window["box" + this.id + "_after"] === "function"
          ) {
            window["box" + this.id + "_after"].call(null, {
              setOption: this.setOption,
              setData: this.setData,
              on: this.on,
              emit: this.emit,
            });
          }
        });
      });
    },
    update() {
      $.get("./map/" + this.config.climecode + ".json", (res) => {
        window.echarts.registerMap(this.config.climecode, res);
        window._charts[this.id].setOption(this.config.option, true);
      });
    },
    resize() {
      window._charts[this.id].resize();
    },
  },
};
/**
 * 图表组件
 */
const vChart = {
  template: `
      <div style="width: 100%; height: 100%" ref="chart"></div>
    `,
  name: "v-chart",
  mixins: [commonMixin],
  methods: {
    init() {
      if (!window._charts) {
        window._charts = {};
      }
      this.$nextTick(() => {
        window._charts[this.id] = window.echarts.init(this.$refs.chart);

        window._charts[this.id].setOption(this.config, true);

        if (
          window["box" + this.id + "_after"] &&
          typeof window["box" + this.id + "_after"] === "function"
        ) {
          window["box" + this.id + "_after"].call(null, {
            setOption: this.setOption,
            setData: this.setData,
            on: this.on,
            emit: this.emit,
          });
        }
      });
    },
    update() {
      window._charts[this.id].setOption(this.config, true);
    },
  },
};

/**
 * 自定义组件
 */
const vHtml = {
  template: `
      <div class="v-s-html">
      <component v-if="config.render" :is="config.render"></component>
      <div class="v-s-html-content" v-html="htmlStyle"></div>
      </div>
    `,
  name: "v-html",
  mixins: [commonMixin],
  methods: {
    init() {
      if (
        window["box" + this.id + "_after"] &&
        typeof window["box" + this.id + "_after"] === "function"
      ) {
        window["box" + this.id + "_after"].call(null, {
          setOption: this.setOption,
          setData: this.setData,
          on: this.on,
          emit: this.emit,
        });
      }
    },
  },
  computed: {
    htmlStyle() {
      return `<style>${this.config._css}</style>${this.config._html}`;
    },
  },
};
/**
 * 选项卡组件
 */
const vTabs = {
  template: `
      <ul class="v-s-tabs">
      <li
          v-for="item in config.tab"
          :key="item.id"
          @click="handlerClick(item.id)"
          :style="item.id === action ? actionLiStyle : liStyle"
          :class="{ action: item.id === action }"
      >
        {{ item.name }}
      </li>
      </ul>
    `,
  name: "v-tabs",
  mixins: [commonMixin],
  data() {
    return {
      action: this.config.defaultId,
    };
  },
  methods: {
    init() {
      if (
        window["box" + this.id + "_after"] &&
        typeof window["box" + this.id + "_after"] === "function"
      ) {
        window["box" + this.id + "_after"].call(null, {
          setOption: this.setOption,
          setData: this.setData,
          on: this.on,
          emit: this.emit,
        });
      }
    },
    handlerClick(id) {
      this.action = id;
    },
  },
  computed: {
    liStyle() {
      return {
        width: this.config.width,
        height: this.config.height,
        margin: `0 ${this.config.spacing}px`,
        "font-size": `${this.config.fontSize}px`,
        color: this.config.fontColor,
        background: `${this.config.bgColor} url('${
          this.url + this.config.bgImg
        }')  no-repeat center`,
        border: `${this.config.border.width}px solid ${this.config.border.color}`,
        "line-height": `${
          this.location.height - this.config.border.width * 2
        }px`,
        "text-align": "center",
      };
    },
    actionLiStyle() {
      return {
        width: this.config.width,
        height: this.config.height,
        margin: `0 ${this.config.spacing}px`,
        "font-size": `${this.config.fontSize}px`,
        color: this.config.action.fontColor,
        background: `${this.config.action.bgColor} url('${
          this.url + this.config.action.bgImg
        }')  no-repeat center`,
        border: `${this.config.border.width}px solid ${this.config.action.borderColor}`,
        "line-height": `${
          this.location.height - this.config.border.width * 2
        }px`,
        "text-align": "center",
      };
    },
  },
};
/**
 * 图片组件
 */
const vImage = {
  template: `
      <div class="v-s-image">
      <img
          :src="config.imgurl"
          :style="imgStyle"
          :class="config.rotate ? 'animation' : ''"
          alt=""
      />
      </div>
    `,
  name: "v-image",
  mixins: [commonMixin],
  methods: {
    init() {
      if (
        window["box" + this.id + "_after"] &&
        typeof window["box" + this.id + "_after"] === "function"
      ) {
        window["box" + this.id + "_after"].call(null, {
          setOption: this.setOption,
          setData: this.setData,
          on: this.on,
          emit: this.emit,
        });
      }
    },
  },
  computed: {
    imgStyle() {
      let animationObj = {
        "animation-iteration-count": "infinite",
        "animation-timing-function": "cubic-bezier(0, 0, 1, 1)",
        opacity: this.config.opacity,
      };
      if (this.config.rotate) {
        animationObj["animation-duration"] = `${this.config.speed}s`;
      }
      return animationObj;
    },
  },
};
/**
 * 翻牌器组件
 */
const vCount = {
  template: `
      <div class="v-s-count">
      <div class="box-item">
        <div
            class="number-item"
            v-for="(item, index) in config.data"
            :key="index"
            :style="/\\d+/.test(item) ? numberStyle : symbolStyle"
        >
          <ul ref="numberItem" :style="ulStyle" v-if="/\\d+/.test(item)">
            <li v-for="(it, i) in config.options" :key="i" :style="liStyle">
              {{ it }}
            </li>
            <li v-for="(it, i) in config.options" :key="i" :style="liStyle">
              {{ it }}
            </li>
          </ul>
          <ul ref="numberItem" :style="ulStyle" v-else>
            <li :style="liStyle">{{ item }}</li>
          </ul>
        </div>
      </div>
      <div class="company" v-show="config.iscompany">
        {{ config.ccontent }}
      </div>
      </div>`,
  name: "v-count",
  mixins: [commonMixin],
  methods: {
    update() {
      this.$nextTick(() => {
        this.setNumberTransform();
      });
    },
    init() {
      this.$nextTick(() => {
        this.setNumberTransform();
        if (
          window["box" + this.id + "_after"] &&
          typeof window["box" + this.id + "_after"] === "function"
        ) {
          window["box" + this.id + "_after"].call(null, {
            setOption: this.setOption,
            setData: this.setData,
            on: this.on,
            emit: this.emit,
          });
        }
      });
    },
    setNumberTransform() {
      for (let i = 0; i < this.config.data.length; i++) {
        if (/\d+/.test(this.config.data[i])) {
          this.$refs.numberItem[i].style.transition = "none";
          this.$refs.numberItem[i].style.transform = "translate(0, 0)";

          setTimeout(() => {
            if (i >= this.$refs.numberItem.length) {
              return;
            }
            let index = this.config.options.indexOf(this.config.data[i]);
            this.$refs.numberItem[i].style.transition =
              "transform 1s ease-in-out";
            this.$refs.numberItem[i].style.transform = `translate(0, -${
              (this.config.options.length + index) *
              parseInt(this.location.height)
            }px)`;
          }, i * 150);
        }
      }
    },
  },
  computed: {
    ulStyle() {
      return {
        height: `${this.config.height * this.config.options.length * 2}px`,
      };
    },
    liStyle() {
      return {
        height: `${this.location.height}px`,
        "line-height": `${this.location.height}px`,
      };
    },

    symbolStyle() {
      let style = {
        background: `${this.config.symbolbgColor} url("${this.config.symbolbgImg}") no-repeat center`,
        width: `${this.config.symbolWidth}px`,
        height: "100%",
        margin: `0 ${this.config.pMargin}px`,
        "font-size": `${this.config.fontSize}px`,
        color: this.config.fontColor,
      };

      return style;
    },
    numberStyle() {
      let style = {
        flex: 1,
        width: `${this.config.pWidth}px`,
        height: "100%",
        margin: `0 ${this.config.pMargin}px`,
        "font-size": `${this.config.fontSize}px`,
        color: this.config.fontColor,
        background: `${this.config.pbgColor} url("${this.config.pbgImg}") no-repeat center`,
      };
      return style;
    },
    companyStyle() {
      return {
        "vertical-align": this.config.companypos,
        "font-size": `${this.config.cfontSize}px`,
        color: this.config.cfontColor,
      };
    },
  },
};

/**
 * 文本组件
 *
 */
const vText = {
  template: `
      <div
          class="v-s-text"
          :style="{ overflow: config.lamp ? 'hidden' : 'visible' }"
          :class="config.class"
          onselectstart="return flase"
      >
      <a
          :href="config.isLink ? config.link : 'javascript:void(0);'"
          :style="textStyle"
          :ref="id"
          :class="
        config.lamp
          ? config.reverse
            ? 'text_animation'
            : 'text_animation1'
          : ''
      "
          v-html="text"
      ></a>
      </div>
    `,
  mixins: [commonMixin],
  data() {
    return {
      t: -1,
      text: "",
    };
  },
  methods: {
    update() {
      if (!this.config.dateflag) {
        this.text = this.config.context;
      }
    },
    init() {
      if (this.config.dateflag) {
        this.dateFormat();
        if (this.t >= 0) {
          clearInterval(this.t);
          this.t = -1;
        }
        this.t = setInterval(this.dateFormat, 1000);
      } else {
        this.text = this.config.context;
      }
      if (
        window["box" + this.id + "_after"] &&
        typeof window["box" + this.id + "_after"] === "function"
      ) {
        window["box" + this.id + "_after"].call(null, {
          setOption: this.setOption,
          setData: this.setData,
          on: this.on,
          emit: this.emit,
        });
      }
    },
    dateFormat() {
      this.text = window.dayjs(new Date()).format(this.config.dateformat);
    },
  },
  computed: {
    textStyle() {
      let styleObj = {
        "font-size": `${this.config.fontSize}px`,
        color: this.config.color,
        "letter-spacing": `${this.config.spacing}px`,
        "text-align": this.config.align,
        "font-weight": this.config.weight,
        display: "flex",
        "line-height": `${this.location.height}px`,
        backgroundColor: this.config.backgroundColor,
        "animation-iteration-count": "infinite",
        "animation-timing-function": "cubic-bezier(0, 0, 1, 1)",
        "white-space": "nowrap",
        overflow: this.config.lamp ? "hidden" : "visible",
      };
      if (this.config.lamp) {
        styleObj["animation-duration"] = `${this.config.speed}s`;
      }
      return styleObj;
    },
  },
};

/**
 * 分组组件
 */
const GroupComponent = {
  template: `
      <div v-if="groupHideOrShow" class="v-s-group-component" :style="positionStyle">
      <component :is="config.render"
                 :config="currentConfig"
                 :location="config.location"
                 :id="id"
                 :request="config.request"></component>
      </div>
    `,
  props: {
    config: {
      type: Object,
    },
    groupVar: {
      type: Object,
    },
    id: {
      type: String,
    },
  },
  setup(props) {
    let currentConfig = Vue.ref(merge(props.config.option, props.config.data));
    Vue.watch(
      () => props.config.option,
      (nv) => {
        currentConfig.value = merge(nv, props.config.data);
      },
      {
        deep: true,
      }
    );
    Vue.watch(
      () => props.config.data,
      (nv) => {
        currentConfig.value = merge(props.config.option, nv);
      },
      {
        deep: true,
      }
    );

    return {
      currentConfig,
    };
  },
  computed: {
    positionStyle() {
      // if(this.config.other.group && window.groupVar[this.config.other.group[0]] === this.config.other.group){
      //
      // }

      return {
        width: this.config.location.width + "px",
        height: this.config.location.height + "px",
        top: this.config.location.y + "px",
        left: this.config.location.x + "px",
      };
    },
    groupHideOrShow() {
      if (this.config.other.group === "") {
        return true;
      }
      if (!this.groupVar[this.config.other.group[0]]) {
        return true;
      }
      return (
        this.groupVar[this.config.other.group[0]] === this.config.other.group
      );
    },
  },
  components: {
    "v-text": vText,
    "v-count": vCount,
    "v-image": vImage,
    "v-tabs": vTabs,
    "v-html": vHtml,
    "v-chart": vChart,
    "v-map-chart": vMapChart,
    "v-table": vTable,
  },
};

const App = {
  template: `
      <div class="v-s-view" :style="screenStyle">
      <v-group-component v-for="(item,key) in components"
                         :key="key"
                         :config="item"
                         :id="key"
                         :group-var="groupVar"
      ></v-group-component>
      </div>
    `,
  components: {
    "v-group-component": GroupComponent,
  },
  setup() {
    // 所有数据
    const config = window.__config;
    // 请求前缀
    if (config.canvasConfig.requestPrefix) {
      window.$path = config.canvasConfig.requestPrefix;
    }
    // 图片前缀
    if (config.canvasConfig.imagePrefix) {
      window.$imagePath = config.canvasConfig.requestPrefix;
    }
    // 对页面响应进行处理
    let adaptX = Vue.ref(1);
    let adaptY = Vue.ref(1);
    // 是否响应

    if (config.canvasConfig.adapt || window.$adapt) {
      function computedAdapt(e) {
        const interfaceHeight = document.documentElement.clientHeight;
        const interfaceWidth = document.documentElement.clientWidth;
        adaptX.value = interfaceWidth / config.canvasConfig.width;
        adaptY.value = interfaceHeight / config.canvasConfig.height;
      }
      computedAdapt();
      window.onresize = computedAdapt;
    }
    const screenStyle = Vue.computed(() => {
      return {
        transform: "scale(" + adaptX.value + "," + adaptY.value + ")",
        width: config.canvasConfig.width + "px",
        height: config.canvasConfig.height + "px",
        background: `${config.canvasConfig.backgroundColor} url('${config.canvasConfig.backgroundImage}')`,
      };
    });

    const components = Vue.reactive(config.config);
    const groupVar = Vue.reactive({});
    // 修改组
    window.PubSub.subscribe("change-group", (name, data) => {
      console.log(name, data);
    });
    // 修改配置
    window.PubSub.subscribe("set-option", (name, data) => {
      if (components[data.id]) {
        Object.assign(components[data.id].option, data.data);
      }
    });
    // 修改数据
    window.PubSub.subscribe("set-data", (name, data) => {
      if (components[data.id]) {
        Object.assign(components[data.id].data, data.data);
      }
    });
    return {
      screenStyle,
      components,
      groupVar,
    };
  },
};

const app = Vue.createApp(App);
app.component("v-chulajsh", {
  props: {
    item: {
      type: Object,
    },
  },
  template: `
      <strong>{{ item.chulajsh }}</strong>
    `,
});
app.mount("#app");
